package com.ecoolex.ying.space.admin.graphql;

import java.util.List;
import java.util.stream.Collectors;

import org.apache.dubbo.config.annotation.Reference;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.lang.NonNull;

import com.google.common.collect.Lists;
import com.alibaba.fastjson.JSONArray;
import com.ecoolex.framework.common.enums.ResultCode;
import com.ecoolex.framework.common.pojo.Page;
import com.ecoolex.framework.common.pojo.Pagination;
import com.ecoolex.framework.common.pojo.Sorting;
import com.ecoolex.framework.common.util.Assert;
import com.ecoolex.framework.common.util.BeanUtil;
import com.ecoolex.framework.common.util.Check;
import com.ecoolex.framework.modularize.api.auth.admin.AdminMemberAuthority;
import com.ecoolex.framework.modularize.api.auth.annotation.AdminAuthoritativeRegister;
import com.ecoolex.framework.modularize.api.auth.user.ConsumerMember;
import com.ecoolex.framework.modularize.api.auth.user.ConsumerMemberManager;
import com.ecoolex.framework.modularize.api.service.audit.AuditRecord;
import com.ecoolex.framework.modularize.api.service.audit.AuditService;
import com.ecoolex.framework.modularize.api.service.storage.FileSize;
import com.ecoolex.framework.modularize.api.service.storage.MimeType;
import com.ecoolex.framework.modularize.api.service.storage.StorageInfo;
import com.ecoolex.framework.modularize.api.service.storage.StorageService;
import com.ecoolex.framework.modularize.api.service.storage.Upload;
import com.ecoolex.framework.modularize.api.service.storage.UploadLimit;
import com.ecoolex.framework.modularize.api.service.storage.UploadSource;
import com.ecoolex.framework.modularize.api.service.storage.process.ImageProcess;
import com.ecoolex.framework.web.api.graphql2.annotation.GraphQL2Module;
import com.ecoolex.framework.web.api.graphql2.annotation.GraphQL2Module.Type;
import com.ecoolex.framework.web.api.graphql2.annotation.MutationField;
import com.ecoolex.framework.web.api.graphql2.annotation.QueryField;
import com.ecoolex.framework.web.api.graphql2.annotation.Source;
import com.ecoolex.framework.web.api.graphql2.annotation.TypeField;
import com.ecoolex.ying.space.admin.core.AdminConstant;
import com.ecoolex.ying.space.entity.OutsourcingGoodsWithBLOBs;
import com.ecoolex.ying.space.entity.OutsourcingPackaged;
import com.ecoolex.ying.space.entity.UserIdentityAuthentication;
import com.ecoolex.ying.space.entity.UserWorks;
import com.ecoolex.ying.space.entity.UserWorks.Column;
import com.ecoolex.ying.space.entity.UserWorksImages;
import com.ecoolex.ying.space.entity.UserWorksOpus;
import com.ecoolex.ying.space.entity.UserWorksOpusItems;
import com.ecoolex.ying.space.entity.UserWorksShopping;
import com.ecoolex.ying.space.entity.UserWorksStatistical;
import com.ecoolex.ying.space.entity.UserWorksVideo;
import com.ecoolex.ying.space.enums.UserWorksStatus;
import com.ecoolex.ying.space.pojo.AddUserWorksDTO;
import com.ecoolex.ying.space.pojo.AddUserWorksOpusDTO;
import com.ecoolex.ying.space.pojo.EditUserWorksDTO;
import com.ecoolex.ying.space.pojo.EditUserWorksOpusDTO;
import com.ecoolex.ying.space.ws.OutsourcingGoodsService;
import com.ecoolex.ying.space.ws.UserIdentityAuthenticationService;
import com.ecoolex.ying.space.ws.UserWorksService;


@GraphQL2Module(type = Type.Admin, description = "用户作品、灵感管理")
@AdminAuthoritativeRegister(parentKey = AdminConstant.AUTH_MODULE_KEY, key = UserWorksGraphql.AUTH, name = "用户作品、灵感管理")
public class UserWorksGraphql {

    public static final String AUTH = AdminConstant.AUTH_MODULE_KEY + "-USERWORKS";

    @Autowired
    private AuditService auditService;

    @Autowired
    private StorageService storageService;

    @Reference
    private UserWorksService userWorksService;

    @Autowired
    private ConsumerMemberManager consumerMemberManager;

    @Reference
    private OutsourcingGoodsService outsourcingGoodsService;

    @Reference
    private UserIdentityAuthenticationService userIdentityAuthenticationService;

    @TypeField(type = UserWorks.class, field = "auditRecord", description = "审核记录")
    public AuditRecord auditRecord(@Source UserWorks source) {
        return auditService.record(source.getAuditRecordId());
    }

    @TypeField(type = UserWorks.class, field = "userWorksStatistical", description = "作品统计数据")
    public UserWorksStatistical getUserWorksStatistical(@Source UserWorks source) {
        return userWorksService.getUserWorksStatisticalByWorksId(source.getWorksId());
    }

    @TypeField(type = UserWorksShopping.class, field = "outsourcingGoods", description = "外购商品")
    public OutsourcingGoodsWithBLOBs getOutsourcingGoods(@Source UserWorksShopping source) {
        return outsourcingGoodsService.getOutsourcingGoodsById(source.getGoodsId());
    }

    @TypeField(type = UserWorksShopping.class, field = "outsourcingPackaged", description = "外购套餐")
    public OutsourcingPackaged getOutsourcingPackaged(@Source UserWorksShopping source) {
        return outsourcingGoodsService.getOutsourcingPackagedById(source.getPackagedId());
    }

    @TypeField(type = UserWorks.class, field = "releaseUser", description = "发布用户")
    public ConsumerMember getCommentUser(@Source UserWorks source) {
        return consumerMemberManager.getByUserId(source.getUserId());
    }

    @TypeField(type = UserWorks.class, field = "coverImage", description = "作品封面图")
    public StorageInfo coverImage(@Source UserWorks source) {
        return storageService.get(source.getCoverImage());
    }

    @TypeField(type = UserWorksOpusItems.class, field = "opusImages", description = "作品栏目图片")
    public List<StorageInfo> opusImages(@Source UserWorksOpusItems source) {
        JSONArray array = JSONArray.parseArray(source.getImages());
        List<String> storageIdList = array.toJavaList(String.class);
        return storageIdList.stream().map(storageId -> storageService.get(storageId)).collect(Collectors.toList());
    }

    @TypeField(type = UserWorksImages.class, field = "images", description = "图文灵感辑的图片")
    public List<StorageInfo> image(@Source UserWorksImages source) {
        JSONArray array = JSONArray.parseArray(source.getImages());
        List<String> storageIdList = array.toJavaList(String.class);
        return storageIdList.stream().map(storageId -> storageService.get(storageId)).collect(Collectors.toList());
    }

    @TypeField(type = UserWorksVideo.class, field = "video", description = "视频灵感辑的视频")
    public StorageInfo video(@Source UserWorksVideo source) {
        return storageService.get(source.getVideo());
    }

    @TypeField(type = UserWorks.class, field = "userWorksImages", description = "图文灵感辑")
    public UserWorksImages userWorksImages(@Source UserWorks userWorks) {
        return userWorksService.getUserWorksImagesByWorksId(userWorks.getWorksId());
    }

    @TypeField(type = UserWorks.class, field = "userWorksVideo", description = "视频灵感辑")
    public UserWorksVideo userWorksVideo(@Source UserWorks userWorks) {
        return userWorksService.getUserWorksVideoByWorksId(userWorks.getWorksId());
    }

    @TypeField(type = UserWorks.class, field = "userWorksOpus", description = "作品")
    public UserWorksOpus userWorksOpus(@Source UserWorks userWorks) {
        return userWorksService.getUserWorksOpusByWorksId(userWorks.getWorksId());
    }

    @TypeField(type = UserWorksOpus.class, field = "userWorksOpusItems", description = "作品栏目")
    public List<UserWorksOpusItems> userWorksOpusItems(@Source UserWorksOpus source) {
        return userWorksService.getUserWorksOpusItemsByWorksId(source.getWorksId());
    }

    @TypeField(type = StorageInfo.class, field = "userWorksShopping", description = "作品购物")
    public List<UserWorksShopping> userWorksShopping(@Source StorageInfo source) {
        return userWorksService.getUserWorksShoppingByStorageId(source.getStorageId());
    }

    @TypeField(type = UserWorks.class, field = "canRelease", description = "能发布")
    public boolean canRelease(@Source UserWorks source) {
        return UserWorksStatus.canRelease(source);
    }

    private static final String AUTH_GET = AUTH + "-GET";

    @QueryField(field = "userWorks", description = "作品、灵感详情")
    @AdminAuthoritativeRegister(parentKey = AUTH, key = AUTH_GET, name = "用户作品、灵感详情")
    public UserWorks get(@NonNull Integer worksId, AdminMemberAuthority user) {
        user.assertAuth(AUTH_GET);
        return userWorksService.getUserWorksById(worksId);
    }

    private static final String AUTH_QUERY = AUTH + "-AUTHQUERY";

    @QueryField(field = "userWorksList", description = "灵感列表")
    @AdminAuthoritativeRegister(parentKey = AUTH, key = AUTH_QUERY, name = "灵感列表")
    public Pagination<UserWorks> query(String title, Integer auditStatus, @NonNull Sorting[] sorts, @NonNull Page page, AdminMemberAuthority user) {
        user.assertAuth(AUTH_QUERY);
        return userWorksService.queryUserWorksList(title, auditStatus, sorts, page);
    }

    private static final String AUTH_QUERY_OPUS = AUTH + "-AUTHQUERYOPUS";

    @QueryField(field = "userWorksOpusList", description = "作品列表")
    @AdminAuthoritativeRegister(parentKey = AUTH, key = AUTH_QUERY_OPUS, name = "作品列表")
    public Pagination<UserWorks> queryOpus(String title, Integer auditStatus, @NonNull Sorting[] sorts, @NonNull Page page, AdminMemberAuthority user) {
        user.assertAuth(AUTH_QUERY_OPUS);
        return userWorksService.queryUserWorksOpusList(title, auditStatus, sorts, page);
    }

    @MutationField(field = "uploadUserWorksCoverImages", description = { "上传作品封面图片" })
    public StorageInfo uploadUserWorksCoverImages(@NonNull Upload request, AdminMemberAuthority user) {
        user.assertLogin();
        UploadSource uploadSource = new UploadSource("UserWorks", "CoverImage");
        UploadLimit uploadLimit = new UploadLimit();
        uploadLimit.setMaxSize(FileSize.MB.byteLength(10));
        uploadLimit.setAllowMimeType(MimeType.IMAGE.commons());

        return storageService.upload(request, uploadSource, uploadLimit, (info) -> {
            // 自适应宽高
            int height = (int) info.getAttributes().get("height");
            int width = (int) info.getAttributes().get("width");

            ImageProcess imageProcess = new ImageProcess();
            imageProcess.setSync(true);
            imageProcess.setKey("preview");
            imageProcess.setQuality(0.8F);
            if (height < width) {
                imageProcess.setZoomMode(AdminConstant.USER_WORKS_COVER_IMAGE_ZOOM_TRANSVERSE);
            } else {
                imageProcess.setZoomMode(AdminConstant.USER_WORKS_COVER_IMAGE_ZOOM_VERTICAL);
            }

            storageService.addProcess(info.getStorageId(), imageProcess);
        });
    }

    @MutationField(field = "uploadUserWorksOpusItemsImages", description = { "上传作品栏目图片" })
    public StorageInfo uploadGoodsImages(@NonNull Upload request, AdminMemberAuthority user) {
        if (!user.auth(AUTH_ADD) && !user.auth(AUTH_EDIT)) {
            user.notAuthority();
        }
        UploadSource uploadSource = new UploadSource("UserWorksOpusItems", "Images");
        UploadLimit uploadLimit = new UploadLimit();
        uploadLimit.setMaxSize(FileSize.MB.byteLength(10));
        uploadLimit.setAllowMimeType(MimeType.IMAGE.commons());

        return storageService.upload(request, uploadSource, uploadLimit);
    }

    private static final String AUTH_ADD = AUTH + "-ADD";

    @MutationField(field = "addUserWorksOpus", description = "添加用户作品")
    @AdminAuthoritativeRegister(parentKey = AUTH, key = AUTH_ADD, name = "添加用户作品")
    public UserWorks addUserWorksOpus(@NonNull AddUserWorksDTO addUserWorksDTO, @NonNull AddUserWorksOpusDTO addUserWorksOpusDTO, @NonNull Integer userId, AdminMemberAuthority user) {
        user.assertAuth(AUTH_ADD);
        // 校验传入的userId是否在用户认证表中是否存在
        UserIdentityAuthentication userIdentityAuthentication = userIdentityAuthenticationService.getByUserId(userId);
        Assert.isTrue(Check.notNull(userIdentityAuthentication), ResultCode.VERIFY.build(1), "平台官方用户不存在");
        return userWorksService.addUserWorksOpus(addUserWorksDTO, addUserWorksOpusDTO, userId, user.userName());
    }

    private static final String AUTH_RELEASE = AUTH + "-RELEASE";

    @MutationField(field = "releaseUserWorks", description = "发布用户作品")
    @AdminAuthoritativeRegister(parentKey = AUTH, key = AUTH_RELEASE, name = "发布用户作品")
    public boolean releaseUserWorks(@NonNull Integer worksId, AdminMemberAuthority user) {
        user.assertAuth(AUTH_RELEASE);
        UserWorks userWorks = userWorksService.getUserWorksById(worksId);
        Assert.isTrue(Check.notNull(userWorks), ResultCode.VERIFY.build(1), "作品不存在");
        return userWorksService.releaseUserWorks(userWorks, user.userName());
    }

    private static final String AUTH_EDIT = AUTH + "-EDIT";

    @MutationField(field = "editUserWorksOpus", description = "编辑用户作品")
    @AdminAuthoritativeRegister(parentKey = AUTH, key = AUTH_EDIT, name = "编辑用户作品")
    public UserWorks editUserWorksOpus(@NonNull EditUserWorksDTO editUserWorksDTO, @NonNull EditUserWorksOpusDTO editUserWorksOpusDTO, @NonNull Integer userId, AdminMemberAuthority user) {
        user.assertAuth(AUTH_EDIT);
        UserWorks old = userWorksService.getUserWorksById(editUserWorksDTO.getWorksId());
        Assert.isTrue(Check.notNull(old), ResultCode.VERIFY.build(1), "作品不存在");
        // 校验传入的userId是否在用户认证表中是否存在
        UserIdentityAuthentication userIdentityAuthentication = userIdentityAuthenticationService.getByUserId(userId);
        Assert.isTrue(Check.notNull(userIdentityAuthentication), ResultCode.VERIFY.build(2), "平台官方用户不存在");
        BeanUtil.copy(editUserWorksDTO,
            old,
            Lists.newArrayList(Column.deleted, Column.createUser, Column.createTime).stream().map(
                Column::getJavaProperty).toArray(String[]::new));
        return userWorksService.editUserWorksOpus(old, editUserWorksOpusDTO, userId, user.userName());
    }

    private static final String AUTH_DEL = AUTH + "-DEL";

    @MutationField(field = "delUserWorksOpus", description = "删除用户作品")
    @AdminAuthoritativeRegister(parentKey = AUTH, key = AUTH_DEL, name = "删除用户作品")
    public boolean delUserWorksOpus(@NonNull Integer worksId, AdminMemberAuthority user) {
        user.assertAuth(AUTH_DEL);
        UserWorks old = userWorksService.getUserWorksById(worksId);
        Assert.isTrue(Check.notNull(old), ResultCode.VERIFY.build(1), "作品不存在");

        userWorksService.deleteUserWorksOpus(old, user.userName());
        return true;
    }
}
